home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / Registration / Registration.m < prev    next >
Text File  |  1992-12-19  |  22KB  |  922 lines

  1. /*
  2.  * (C) 1992 Simson Garfinkel and Associates, Inc.
  3.  *
  4.  * NeXTSTEP developers may freely use and redistribute this software as long
  5.  * as credit is given to Simson Garfinkel and Associates.
  6.  *
  7.  * EXPORT RESTRICTIONS:
  8.  *
  9.  * You may not ship the source-code module des.c outside of the US or canada.
  10.  *
  11.  * You may ship a program which uses the des.o compiled module outside of the
  12.  * United States to any type T or type V country as long as you do not provide
  13.  * cryptographic services to the user in your program and you clearly
  14.  * declare "commodity control number 5D11A" on your export declaration.
  15.  *
  16.  * Type T countries include all countries in the Western Hemisphere except Cuba.
  17.  * Type V countries include all countries in the Eastern Hemisphere except
  18.  * the previous communist block countries and the People's Republic of China,
  19.  * Vietnam, Cambodia, and Laos.
  20.  *
  21.  * For further information, contact the Office of Export Control:
  22.  *
  23.  *    Bureau of Export Administration
  24.  *    P.O. Box 273
  25.  *    Washington, DC 20044
  26.  *    202-377-2694
  27.  */
  28.  
  29. #import <appkit/appkit.h>
  30.  
  31. #import "Registration.h"
  32.  
  33. #import <netdb.h>
  34. #import <pwd.h>
  35. #import <NXCType.h>
  36.  
  37.  
  38. /* Network Registration Stuff
  39.  *
  40.  * "embedded" is our embedded registration string, for stamped binaries.
  41.  * It contains our current network token.
  42.  * Is is decrypted when we are running.
  43.  */
  44.  
  45.  
  46. struct    registration_string embedded = 
  47. {
  48. SERIAL_GUARD_1,SERIAL_GUARD_2,
  49. 0,                    /* ctime */
  50. 0,                    /* mtime */
  51. 0,                    /* checksum */
  52. 0,0,0,0,0,0,0,0,0,0,            /* ls */
  53.  
  54. 0,0,0,0,0,0,0,0,0,0,
  55. 0,0,0,0,0,0,0,0,0,0,
  56. 0,0,0,0,0,0,0,0,0,0,
  57. 0,0,0,0,0,0,0,0,0,0,
  58. 0,0,0,0,0,0,0,0,0,0,
  59. 0,0,0,0,0,0,0,0,0,0,
  60. 0,0,0,0,0,0,0,0,0,0,
  61. 0,0,0,0,0,0,0,0,0,0,            /* name */
  62. SERIAL_GUARD_1,SERIAL_GUARD_2    
  63. };
  64.  
  65.  
  66. #define    REG        "SingleUserRegistrationString" 
  67. #define    ANNOUNCEMENT_FREQUENCY 60.0 * 10    /* how often to announce ourselves */
  68.  
  69. /* Static variables */
  70.  
  71. static    port_name_t    myMachPort;
  72. static    int        send_sock;        /* the talking socket */
  73. static    int        recv_sock;        /* receiving socket */
  74. static    int        recv_fd;        /* receiving fd */
  75. static    mutex_t        randomt;        /* mutex for random number genreator */
  76. static    long        otherHosts[1024];     /* other hosts running with our license */
  77. static    int        numOtherHosts;
  78. static    DPSTimedEntry    announcementTE;
  79. static    DPSTimedEntry    expiredTE;
  80. static    int        licensed;    /* are we licensed? */
  81. static    id        registrationPanel;
  82. static    id         licensePanel;
  83. static    long        start_time;
  84. static    char        username[10];
  85. static    char        person[64];
  86. static    long        session_number;
  87.  
  88. /* for probing on licensing */
  89. static    int        probes_found;
  90. static    unsigned char    probing_num[3];    /* number we are probing */
  91. static    char        probed_person[9];
  92. static    char        probed_username[64];
  93. static    char        probed_host[64];
  94.  
  95.  
  96. #import "RegSupport.m"
  97.  
  98. /****************************************************************
  99.  MACH MESSAGE FUNCTIONS
  100.  ****************************************************************/
  101.  
  102.  
  103. /* structure for mach messaging */
  104. typedef struct {
  105.     msg_header_t     h;
  106.     msg_type_t       t1;
  107.     int        command;
  108.     msg_type_t       t2;
  109.     const char     *data;
  110. } myMessage;
  111.  
  112.  
  113. #define    BROADCAST 0xffffffff
  114. #define    PING_EVERYBODY 1
  115. #define PONG_EVERYBODY 2
  116.  
  117. /* Send a mach message to the main thread */
  118. void    message_main_thread(int command,const char *data)
  119. {
  120.     myMessage    msg;
  121.     
  122.     memset(&msg,0,sizeof(msg));    /* zero my message */
  123.  
  124.     msg.h.msg_simple    = TRUE;
  125.     msg.h.msg_size         = sizeof(msg);
  126.     msg.h.msg_type         = MSG_TYPE_NORMAL; /* normal message */
  127.     msg.h.msg_local_port     = 0;
  128.     msg.h.msg_remote_port     = myMachPort;
  129.  
  130.     /* fill in the type descriptor */
  131.     msg.t1.msg_type_name     = MSG_TYPE_INTEGER_32;
  132.     msg.t1.msg_type_size     = 32;
  133.     msg.t1.msg_type_number     = 1;
  134.     msg.t1.msg_type_inline     = YES;
  135.     msg.t1.msg_type_longform = FALSE;
  136.     msg.t1.msg_type_deallocate = FALSE;
  137.  
  138.     /* fill in the type descriptor */
  139.     msg.t2.msg_type_name     = MSG_TYPE_STRING_C;
  140.     msg.t2.msg_type_size     = 32;
  141.     msg.t2.msg_type_number     = 1;
  142.     msg.t2.msg_type_inline     = FALSE;
  143.     msg.t2.msg_type_longform = FALSE;
  144.     msg.t2.msg_type_deallocate = FALSE;
  145.  
  146.     msg.command    = command;
  147.     msg.data    = data;
  148.         
  149.     msg_send(&msg.h,SEND_NOTIFY,0);    /* send and don't wait */
  150. }
  151.  
  152. /* This gets called in the main thread from message_main_thread
  153.  */
  154. DPSPortProc    portListener(msg_header_t *msgp,void *userData)
  155. {
  156.     myMessage    *msg = (myMessage *)msgp;
  157.     char        *data;
  158.  
  159.     data    = alloca(strlen(msg->data)+1);
  160.     strcpy(data,msg->data);
  161.  
  162.     switch(msg->command){
  163.      case C_PRINT:
  164.        NXRunAlertPanel(0,data,0,0,0);
  165.        return 0;
  166.  
  167.      case C_DUPLICATE_SINGLE_USER:
  168.        NXRunAlertPanel("License Violation",
  169.                "%s is already using your single user license string",
  170.                "Abort program",0,0,data);
  171.        [NXApp fatalError];
  172.        return 0;
  173.        
  174.      case C_TOO_MANY_NETWORK:
  175.        NXRunAlertPanel("License Violation",
  176.                "More than %d copies of this program are already running on your network.",
  177.                "Abort program",0,0,lsNumUsers(&embedded.ls));
  178.        [NXApp fatalError];
  179.        return 0;
  180.  
  181.                
  182.     }
  183.     return 0;
  184. }
  185.  
  186.  
  187. /****************************************************************
  188.   UDP STUFF
  189.  ****************************************************************/
  190.  
  191. /*
  192.  * udp_announcer:
  193.  * Announce my whereabouts to the world.
  194.  * Randomly pause between 1 and 10 seconds, which should be sufficient for most
  195.  * networks.
  196.  */
  197. static    void udp_announcer(int address)
  198. {
  199.     struct  sockaddr_in sin;
  200.     struct    regNetToken     nt;
  201.     int    pause;
  202.     long    now;
  203.     long    duration;
  204.  
  205.     if(address!=PING_EVERYBODY){
  206.         mutex_lock(randomt);
  207.         pause    = random() % RANDOM_SLEEP_TIME;
  208.         mutex_unlock(randomt);
  209.         sleep(pause);
  210.     }
  211.  
  212.     
  213.     time(&now);
  214.  
  215.     duration = now - start_time;
  216.  
  217.     memset(&nt,0,sizeof(nt));
  218.     nt.version        = 0;
  219.     strcpy(nt.username,username);
  220.     strcpy(nt.person,person);
  221.     nt.ls            = embedded.ls;
  222.     nt.session_number    = session_number;
  223.     nt.time[0]        = duration & 0xff;
  224.     nt.time[1]        = (duration >> 8) & 0xff;
  225.     nt.time[2]        = (duration >> 16) & 0xff;
  226.     nt.time[3]        = (duration >> 24) & 0xff;
  227.     nt.command        = C_PONG;
  228.     memset(&nt.userData,0,sizeof(nt.userData));
  229.  
  230.     switch(address){
  231.           case PING_EVERYBODY:
  232.         address        = BROADCAST;
  233.         nt.command    = C_PING;
  234.         break;
  235.           case PONG_EVERYBODY:
  236.         address        = BROADCAST;
  237.         nt.command    = C_PONG;
  238.         break;
  239.     }
  240.  
  241.     sin.sin_family        = AF_INET;
  242.     sin.sin_port        = PRODUCT_UDP_PORT;    /* our port */
  243.     *(int *)&sin.sin_addr    = address;
  244.  
  245.     sendto(send_sock,&nt,sizeof(nt),0,(struct sockaddr *)&sin,sizeof(sin));
  246. }
  247.  
  248.  
  249. /* duplicate_ls():
  250.  *
  251.  * Called when somebody tells me they are using my accession number.
  252.  * 1. Ignore them if they were started after we were.
  253.  * 2. If they are using our accession number on a SINGLE USER license,
  254.  * 3. If they are using a multi-user number, then count how many
  255.  *    people are left
  256.  */
  257. void    duplicate_ls(int fromaddr,struct regNetToken *nt)
  258. {
  259.     long    now;
  260.     long    my_duration,their_duration;
  261.     char    buf[1024];
  262.     char    buf2[1024];
  263.     int    i;
  264.  
  265.     /* First tell them that something is amis */
  266.  
  267.     time(&now);
  268.     my_duration = now - start_time;
  269.  
  270.     their_duration    = nt->time[3]<<24 | nt->time[2]<<16 | nt->time[1]<<8 | nt->time[0];
  271.  
  272.     if(my_duration+REG_WINDOW > their_duration){
  273.  
  274.        /* They haven't been running as long as we have been. */
  275.  
  276.        if(embedded.ls.flag & REG_SINGLEUSER){
  277.  
  278.           /* but they are using our single user string! */
  279.  
  280.           sprintf(buf,"%s (%s) on %s is trying to run this application with your "
  281.               "single-user license string.",
  282.               nt->person,nt->username,hostName(fromaddr,buf2));
  283.           message_main_thread(C_PRINT,buf);
  284.        }
  285.  
  286.  
  287.        return;            /* don't annoy our user any more */
  288.     }
  289.  
  290.     if(embedded.ls.flag & REG_SINGLEUSER){
  291.  
  292.        /* we came second on single-user string */
  293.        sprintf(buf,"%s (%s) on %s",
  294.            nt->person,
  295.            nt->username,
  296.            hostNumberToAscii(fromaddr,buf2));
  297.        message_main_thread(C_DUPLICATE_SINGLE_USER,buf);
  298.     }
  299.     
  300.     for(i=0;i<numOtherHosts;i++){
  301.        if(otherHosts[i]==fromaddr) return; /* already got this host */
  302.     }
  303.     otherHosts[numOtherHosts++] = fromaddr;
  304.  
  305.     /* More than maximum allowed hosts? */
  306.  
  307.  
  308.     if(numOtherHosts >= lsNumUsers(&embedded.ls)){
  309.        message_main_thread(C_TOO_MANY_NETWORK,"");
  310.     }
  311.  
  312. }
  313.  
  314.  
  315.  
  316. /* udp_listener():
  317.  *
  318.  * Listen for incoming UDP commands and execute them.
  319.  */
  320.  
  321. static    void udp_listener(void *userData)
  322. {
  323.     struct    sockaddr_in from;
  324.     int    fromlen;
  325.     long    fromaddr;
  326.     char    received_udp[4096];
  327.     int    cc;
  328.  
  329.     while(1){
  330.         memset(&from,0,sizeof(from));
  331.         fromlen = sizeof(from);
  332.         cc    = recvfrom(recv_sock, received_udp, sizeof(received_udp),
  333.                    0, (struct sockaddr *)&from, &fromlen);
  334.  
  335.         fromaddr=*(int *)&from.sin_addr;;
  336.         if(cc==sizeof(struct regNetToken)){
  337.            char    hbuf[256];
  338.  
  339.             struct    regNetToken     *nt = (struct regNetToken *)received_udp;
  340.             
  341.  
  342.             if(nt->session_number==session_number){
  343.                 /* got a message from myself.  Ignore */
  344.                 continue;
  345.             }
  346.  
  347.            
  348.            /* Check for match with our license string */
  349.            if(!memcmp(nt->ls.num,embedded.ls.num,3)){
  350.               duplicate_ls(fromaddr,nt); 
  351.            }
  352.  
  353.             /* decode command */
  354.             switch(nt->command){
  355.                   case C_PING:
  356.                 cthread_fork((cthread_fn_t)udp_announcer,(any_t)fromaddr);
  357.                 break;
  358.                   case C_PRINT:
  359.                 {
  360.                     char    *buf;
  361.  
  362.                     buf    = alloca(1024+strlen(nt->userData));
  363.                     
  364.                     sprintf(buf,"Message from %s on %s: %s",
  365.                         nt->username,
  366.                         hostNumberToAscii(fromaddr,hbuf),
  367.                         nt->userData);
  368.                     message_main_thread(C_PRINT,buf);
  369.                 }
  370.                 break;
  371.                   case C_PONG:
  372.                 /* Check for match with probe */
  373.                 if(!memcmp(nt->ls.num,probing_num,3)){
  374.                     strcpy(probed_person,nt->person);
  375.                     strcpy(probed_username,nt->username);
  376.                     strncpy(probed_host,hostName(fromaddr,hbuf),63);
  377.                     probed_host[63] = 0;
  378.                     probes_found++;
  379.                 }
  380.                 break;
  381.             }
  382.         }
  383.     }
  384. }
  385.  
  386.  
  387.  
  388. /* called by announcement TE */
  389. static    void    announcement_handler()
  390. {
  391.     if(embedded.ls.flag & REG_DEMO){
  392.         /* don't announce if we are a demo copy */
  393.         return;
  394.     }
  395.     cthread_fork((cthread_fn_t)udp_announcer,(any_t)PONG_EVERYBODY);
  396. }
  397.  
  398. /****************************************************************
  399.   INITIALIZATION
  400.  ****************************************************************/
  401.  
  402. static    void    network_init()
  403. {
  404.     struct  sockaddr_in sin;
  405.     struct    passwd    *pw;
  406.  
  407.  
  408.     /* NETWORK INITIALIZATION */
  409.  
  410.     memset(otherHosts,0,sizeof(otherHosts));
  411.     memset(probing_num,0,sizeof(probing_num));
  412.  
  413.     numOtherHosts = 0;
  414.  
  415.     /* set up connections for listening */
  416.     memset(&sin,0,sizeof(sin));
  417.     sin.sin_family    = AF_INET;
  418.     sin.sin_port    = PRODUCT_UDP_PORT;    /* our port */
  419.     recv_sock    = socket(AF_INET,SOCK_DGRAM,0); /* get a socket */
  420.     if(recv_sock<0){
  421.         NXRunAlertPanel(0,"Could not create Internet socket.","Abort program",0,0);
  422.         [NXApp fatalError];
  423.     }
  424.     recv_fd     = bind(recv_sock,(struct sockaddr *)&sin,sizeof(sin));
  425.     if(recv_fd<0){
  426.         NXRunAlertPanel(0,"Could not bind to network.  You are probably "
  427.                 "running another copy of %s on this computer.",
  428.                 "Abort program",0,0,[NXApp appName]);
  429.         [NXApp fatalError];
  430.     }
  431.  
  432.  
  433.     randomt    = mutex_alloc();
  434.     srandom(time(&start_time));
  435.  
  436.     pw    = getpwuid(getuid());
  437.  
  438.     memset(username,0,sizeof(username));
  439.     memset(person,0,sizeof(person));
  440.     strncpy(username,pw->pw_name,sizeof(username));
  441.     strncpy(person,pw->pw_gecos,sizeof(person));
  442.     person[sizeof(person)-1]    = 0;
  443.     username[sizeof(username)-1]    = 0;
  444.  
  445.     session_number    = random();
  446.  
  447.     port_allocate(task_self(),&myMachPort);
  448.     send_sock    = socket(AF_INET,SOCK_DGRAM,0);
  449.     DPSAddPort(myMachPort,(DPSPortProc)portListener,8192,0,NX_BASETHRESHOLD);
  450.  
  451.     cthread_fork((cthread_fn_t)udp_listener,0);
  452.     cthread_fork((cthread_fn_t)udp_announcer,(any_t)PING_EVERYBODY);
  453.  
  454.     announcementTE = DPSAddTimedEntry(ANNOUNCEMENT_FREQUENCY,
  455.                       announcement_handler,0,NX_BASETHRESHOLD);
  456.  
  457. }
  458.  
  459. static    void    license_init()
  460. {
  461.     /* See if we are licensed */
  462.     const char     *reg;
  463.     const char    *appName = [NXApp appName];
  464.     BOOL        branded=YES;
  465.     char        key[9];
  466.     char         ks[16][8];
  467.  
  468.     licensed= NO;
  469.     reg    = NXGetDefaultValue(appName,REG);
  470.     if(reg){
  471.         /* If we have a default value, overwrite value stored in binary */
  472.         hex_to_binary(reg,&embedded,sizeof(embedded)); 
  473.         branded=NO;
  474.     }
  475.  
  476.     /* Decrypt it */
  477.     asciiToKey(PRODUCT_PASSWORD,key);
  478.     desinit(0);
  479.     dessetkey(ks,key);
  480.     dedes(ks,&embedded.checksum);
  481.     
  482.  
  483.     /* Now check to see if string is legit */
  484.     if(checksum2(&embedded,sizeof(embedded))) return;
  485.  
  486.     if(embedded.guard1[0]!=SERIAL_GUARD_1 ||
  487.        embedded.guard1[1]!=SERIAL_GUARD_2 ||
  488.        embedded.guard2[0]!=SERIAL_GUARD_1 ||
  489.        embedded.guard2[1]!=SERIAL_GUARD_2){
  490.  
  491.         /* serial guard is not present */
  492.         memset(&embedded,0,sizeof(embedded));
  493.         return;
  494.     }
  495.  
  496.     /* Make sure we are the right product */
  497.     if(embedded.ls.product != PRODUCT_CODE) return;    /* doesn't match */
  498.  
  499.     /* See if it has expired */
  500.     if(embedded.ls.flag & REG_START){
  501.         long    t;
  502.         struct    tm *tm;
  503.  
  504.         time(&t);
  505.         tm    = localtime(&t);
  506.         if(   ((embedded.ls.start & 0x40) >> 4) < (tm->tm_mon+1)
  507.            || ((embedded.ls.start & 0x04) + 1992) < (tm->tm_year+1900)){
  508.  
  509.             [NXApp perform:@selector(notifyLicenseExpired:) with:nil
  510.                afterDelay:1000 cancelPrevious:NO];
  511.             memset(&embedded,0,sizeof(embedded));
  512.             return;
  513.         }
  514.     }
  515.  
  516.     if(embedded.ls.flag & REG_END){
  517.         long    t;
  518.         struct    tm *tm;
  519.  
  520.         time(&t);
  521.         tm    = localtime(&t);
  522.         if(   ((embedded.ls.end & 0x40) >> 4) > (tm->tm_mon+1)
  523.            || ((embedded.ls.end & 0x04) + 1992) > (tm->tm_year+1900)){
  524.  
  525.             [NXApp perform:@selector(notifyLicenseExpired:) with:nil
  526.                afterDelay:1000 cancelPrevious:NO];
  527.             memset(&embedded,0,sizeof(embedded));
  528.             return;
  529.         }
  530.     }
  531.  
  532.     /* See if the file was moved and we are a network license */
  533.  
  534.     if(branded){
  535.         struct stat sbuf;
  536.  
  537.         if(embedded.ls.flag & REG_DEMO){
  538.            NXRunAlertPanel(0,"This is a demo version",0,0,0);
  539.            licensed = YES;
  540.            return;
  541.         }
  542.  
  543.  
  544.         /* Not a demo.  See if it has been moved */
  545.  
  546.         if(stat(NXArgv[0],&sbuf)){
  547.             NXRunAlertPanel(0,"Cannot access executable: %s",0,0,0,
  548.                     NXArgv[0]);
  549.             memset(&embedded,0,sizeof(embedded));
  550.             return;
  551.         }
  552.         if(embedded.mtime+10 < sbuf.st_mtime){
  553.  
  554.            /* Only do this if we are not a demo */
  555.            NXRunAlertPanel(0,
  556.                    "Branded file has been moved and "
  557.                    "must be re-branded.",
  558.                    0,0,0);
  559.            memset(&embedded,0,sizeof(embedded));
  560.            return;
  561.         }
  562.          }
  563.     licensed = YES;
  564. }
  565.  
  566. static    void    demo_expired()
  567. {
  568.     if(licensed){
  569.         DPSRemoveTimedEntry(expiredTE);    /* it got licensed */
  570.         expiredTE = 0;
  571.         return;
  572.     }
  573.     NXRunAlertPanel("Time's up!","This program is not licensed. "
  574.             "Your 2-minute demo period has expired",0,0,0);
  575.     [NXApp    fatalError];
  576. }
  577.  
  578.  
  579. void    registration_init2(DPSTimedEntry teNumber, double now, char *userData)
  580. {
  581.    DPSRemoveTimedEntry(teNumber);    /* remove ourselves */
  582.    network_init();
  583.    license_init();
  584.     
  585.    if(licensed==NO){
  586.       [NXApp    perform:@selector(notifyNotLicensed:) with:nil
  587.      afterDelay:1000 cancelPrevious:NO];
  588.  
  589.       expiredTE = DPSAddTimedEntry(60 * 2.0,
  590.                    demo_expired,0,NX_BASETHRESHOLD);
  591.    }
  592. }
  593.  
  594. /* registration_init():
  595.  *
  596.  * Main entry into the registration package.
  597.  * Must be run from the main thread.
  598.  * May be run as many times as needed.
  599.  * 
  600.  * Schedule the real init process with a TE
  601.  */
  602.  
  603. void    registration_init()
  604. {
  605.     static     inited=0;
  606.  
  607.     if(inited) return;
  608.     inited    = 1;
  609.  
  610.     DPSAddTimedEntry(0.1,(DPSTimedEntryProc)registration_init2,
  611.              0,NX_BASETHRESHOLD);
  612. }
  613.  
  614.  
  615. /* bootstrap myself into the Application class */
  616. @implementation MenuCell(Registration)
  617. +alloc
  618. {
  619.     registration_init();
  620.     return [super alloc];
  621. }
  622.  
  623. +allocFromZone:(NXZone *)zone
  624. {
  625.     registration_init();
  626.     return [super allocFromZone:zone];
  627. }
  628. @end
  629.  
  630. @implementation Application(Registration)
  631. -fatalError
  632. {
  633.     [self terminate:nil];
  634.     exit(0);        /* for the bozos */
  635. }
  636.  
  637. -noisyFatalError
  638. {
  639.     NXRunAlertPanel("Fatal Error",
  640.             "Unable to load Registration Panels from executable. "
  641.             "Execution cannot continue.","Exit Program",0,0);
  642.     [self fatalError];
  643.     exit(0);
  644. }
  645.  
  646. BOOL    check_position(char *start,char *pos)
  647. {
  648.     struct    registration_string *test = (struct registration_string *)pos;
  649.  
  650.     if(test->guard1[0]==SERIAL_GUARD_1 &&
  651.        test->guard1[1]==SERIAL_GUARD_2 &&
  652.        test->guard2[0]==SERIAL_GUARD_1 &&
  653.        test->guard2[1]==SERIAL_GUARD_2){
  654.  
  655.         long    offset = pos-start;
  656.         int    fd;
  657.  
  658.         /* open up the file and write out the new token */
  659.         fd    = open(NXArgv[0],O_RDWR);
  660.         if(!fd){
  661.             NXRunAlertPanel("Branding","Could not open %s for branding",0,0,0,
  662.                     NXArgv[0]);
  663.         }
  664.         lseek(fd,offset,0);
  665.         write(fd,&embedded,sizeof(embedded));
  666.         close(fd);
  667.         return YES;
  668.     }
  669.     return NO;
  670. }
  671.  
  672. -showLicenseStatus
  673. {
  674.     id    status  = NXGetNamedObject("LicenseStatusCell",licensePanel);
  675.     id    user    = NXGetNamedObject("LicenseNameField",licensePanel);
  676.     id    exp    = NXGetNamedObject("ExpField",licensePanel);
  677.     id    userNum = NXGetNamedObject("UserNumberField",licensePanel);
  678.  
  679.     if(!licensed){
  680.         [status     setStringValue:"This program is unlicensed"];
  681.         [user        setStringValue:""];
  682.         [exp        setStringValue:""];
  683.         [userNum    setStringValue:""];
  684.         return self;
  685.     }
  686.  
  687.     if(embedded.ls.flag & REG_SINGLEUSER){
  688.         [status    setStringValue:"Licensed for single-user use."];
  689.         [user    setStringValue:embedded.owner];
  690.     }
  691.     if(embedded.ls.flag & REG_DEMO){
  692.         [status    setStringValue:"Demonstration License"];
  693.         [user    setStringValue:embedded.owner];
  694.     }
  695.     if((embedded.ls.flag & (REG_SINGLEUSER | REG_DEMO))==0){
  696.         char    buf[256];
  697.  
  698.         sprintf(buf,"Network License\n%d copies",lsNumUsers(&embedded.ls));
  699.         [status    setStringValue:buf];
  700.         [user    setStringValue:embedded.owner];
  701.     }
  702.     if(embedded.ls.flag & REG_END){
  703.         char    buf[256];
  704.  
  705.         sprintf(buf,"Expires %d/%d",
  706.             (embedded.ls.end & 0x40) >> 4,
  707.             (embedded.ls.end & 0x04) + 92);
  708.         [exp    setStringValue:buf];
  709.     }
  710.     else{
  711.         [exp    setStringValue:""];
  712.     }
  713.     [userNum    setIntValue:(  (embedded.ls.num[0] << 16)
  714.                      + (embedded.ls.num[1] <<  8)
  715.                      + (embedded.ls.num[2] <<  0))];
  716.                      
  717.     return self;
  718. }
  719.  
  720. -registerProgram:sender
  721. {
  722.     NXStream    *str;
  723.     char        *addr;
  724.     int        len,maxlen;
  725.     long        test = SERIAL_GUARD_1;
  726.     char        val = *(unsigned char *)&test;
  727.     struct licenseString    ls;
  728.     const char    *regString;
  729.     const char    *companyName;
  730.     char        *aa;
  731.     unsigned char     *cc = (unsigned char *)&ls;
  732.     struct stat     sbuf;
  733.     char        key[9];
  734.     char         ks[16][8];
  735.  
  736.     /* Check to see if the registration string is valid */
  737.     regString = [NXGetNamedObject("LicenseStringField",registrationPanel) stringValue];
  738.     companyName=[NXGetNamedObject("CompanyNameField",registrationPanel) stringValue];
  739.  
  740.     if(!regString) [self    noisyFatalError];
  741.  
  742.     /* Convert to a license token */
  743.     hex_to_binary(regString,&ls,sizeof(ls));
  744.  
  745.     /* Decrypt the token */
  746.     asciiToKey(PRODUCT_PASSWORD,key);
  747.     desinit(0);
  748.     dessetkey(ks,key);
  749.     dedes(ks,cc+2);
  750.     dedes(ks,cc);
  751.  
  752.     if(checksum(&ls,sizeof(ls))){
  753.         NXRunAlertPanel("License","Invalid license string",0,0,0);
  754.         return nil;
  755.     }
  756.     
  757.     if(strlen(companyName)==0){
  758.         NXRunAlertPanel("License","Name may not be blank",0,0,0);
  759.         return nil;
  760.     }
  761.  
  762.     if(stat(NXArgv[0],&sbuf)){
  763.         NXRunAlertPanel("License","Cannot access executable: %s",0,0,0,
  764.                 NXArgv[0]);
  765.         return nil;
  766.     }
  767.  
  768.     /* If this is a single-user string, see if anybody else is using it */
  769.     if(ls.flag & REG_SINGLEUSER){
  770.         probes_found    = 0;
  771.         memcpy(probing_num,ls.num,3);
  772.         udp_announcer(PING_EVERYBODY);  /* ping everybody in this thread */
  773.         sleep(RANDOM_SLEEP_TIME+2);    /* wait for results */
  774.         if(probes_found>0){
  775.             NXRunAlertPanel("License",
  776.                     "That license string is being used by "
  777.                     "%s (%s) on the workstation named '%s.'",
  778.                     "Can't license",0,0,
  779.                     probed_person,probed_username,probed_host);
  780.             return nil;
  781.         }
  782.         memset(probing_num,0,sizeof(probing_num));
  783.     }
  784.  
  785.     licensed    = YES;
  786.  
  787.  
  788.     /* Set up the embedded token */
  789.     memset(&embedded,0,sizeof(embedded));
  790.  
  791.     embedded.guard1[0]     = SERIAL_GUARD_1;
  792.     embedded.guard1[1]    = SERIAL_GUARD_2;
  793.     embedded.guard2[0]    = SERIAL_GUARD_1;
  794.     embedded.guard2[1]    = SERIAL_GUARD_2;
  795.     embedded.ls        = ls;
  796.     time(&embedded.ctime);
  797.     time(&embedded.mtime);
  798.     strncpy(embedded.owner,companyName,sizeof(embedded.owner)-1);
  799.         
  800.     /* calc the checksum */
  801.  
  802.     embedded.checksum    = 0;
  803.     embedded.checksum    = 65536-checksum2(&embedded,sizeof(embedded));
  804.  
  805.     /* Make sure we calculated it properly */
  806.     if(checksum2(&embedded,sizeof(embedded))!=0){
  807.         NXRunAlertPanel(0,"Internal error: checksum not 0.  Cannot license.",0,0,0);
  808.         return nil;
  809.     }
  810.  
  811.     
  812.     [registrationPanel    orderOut:nil];
  813.  
  814.     /* Now encrypt it before writing */
  815.     dessetkey(ks,key);
  816.     endes(ks,&embedded.checksum);
  817.  
  818.  
  819.     /* If this is a single-user license, write it into the defaults database */
  820.     if(ls.flag & REG_SINGLEUSER){
  821.         char    buf[256];
  822.         
  823.         NXWriteDefault(appName,REG,
  824.                    binary_to_hex(&embedded,sizeof(embedded),buf));
  825.  
  826.         NXRunAlertPanel(0,"Registered single-user license",0,0,0);
  827.         goto    end;
  828.     }
  829.  
  830.  
  831.     NXRemoveDefault(appName,REG); /* no longer a single user */
  832.  
  833.     /* Must be demo or multi-user; write to binary */
  834.  
  835.     str    = NXMapFile(NXArgv[0],NX_READONLY);
  836.     NXGetMemoryBuffer(str,&addr,&len,&maxlen);
  837.  
  838.     for(aa=addr;aa<addr+len;aa++){
  839.         if(*aa == val
  840.            && check_position(addr,aa)){
  841.             NXRunAlertPanel(0,"Branded successfully for %d users",
  842.                     0,0,0,lsNumUsers(&embedded.ls));
  843.             goto end;
  844.         }
  845.     }
  846.  
  847.       end:;
  848.     /* Now decrypt the string that's in memory */
  849.     dessetkey(ks,key);
  850.     dedes(ks,&embedded.checksum);
  851.     [self    showLicenseStatus];
  852.  
  853.     return self;
  854. }
  855.  
  856. /* Display License Panel.
  857.  * If program is unlicensed, display the registration panel...
  858.  */
  859. -showLicensePanel:sender
  860. {
  861.     if(!licensePanel){
  862.         [NXApp loadNibSection:"registration.nib" owner:NXApp withNames:YES];
  863.  
  864.         /* wire up everything.  You don't think that we're going to put this
  865.          * in the nib, do you?
  866.          */
  867.         licensePanel = NXGetNamedObject("License Panel",NXApp);
  868.     }
  869.     if(licensePanel==nil)    [NXApp noisyFatalError];
  870.     [self        showLicenseStatus];
  871.  
  872.     if(licensed){
  873.         [[licensePanel     center] makeKeyAndOrderFront:nil]; /* display it */
  874.     }
  875.     else{
  876.         [self        showRegistrationPanel:nil];
  877.     }
  878.     return self;
  879. }
  880.  
  881. /* Display the Registration Panel */
  882. -showRegistrationPanel:sender
  883. {
  884.     if(!registrationPanel){
  885.         [NXApp loadNibSection:"registration.nib" owner:NXApp withNames:YES];
  886.  
  887.         /* wire up everything.  You don't think that we're going to put this
  888.          * in the nib, do you?
  889.          */
  890.         registrationPanel = NXGetNamedObject("Registration Panel",NXApp);
  891.     }
  892.     if(registrationPanel==nil) [NXApp noisyFatalError];
  893.     [NXGetNamedObject("LicenseStringField",registrationPanel) setStringValue:""];
  894.     [NXGetNamedObject("CompanyNameField",registrationPanel) setStringValue:""];
  895.     [[registrationPanel center] makeKeyAndOrderFront:nil]; /* display it */
  896.     return self;
  897.  
  898. }
  899.  
  900. - notifyNotLicensed:sender
  901. {
  902.     NXRunAlertPanel("License","This program is not licensed. "
  903.             "You will only be allowed to run it for 2 minutes.",0,0,0);
  904.     [self    showRegistrationPanel:nil];
  905.     return self;
  906. }
  907.  
  908. - notifyLicenseExpired:sender
  909. {
  910.     NXRunAlertPanel("License","Your license has expired.  "
  911.             "This program is now unlicensed",
  912.             0,0,0);
  913.     return self;
  914.  
  915. }
  916.  
  917. @end
  918.   
  919.  
  920. #import "des.c"
  921.   
  922.